pub mod lib;

use chrono::{Duration, NaiveDate};
use futures::executor::block_on;
use office::{DataType, Excel, Range};
use reqwest::Response;
use reqwest::header::HeaderMap;
use serde_json::{json, value::Value, Map};
use tuleap::tuleap_client::TuleapClient;
use std::{collections::HashMap, thread};
use tuleap::utils::export;
use tuleap::vo::RowData;

const TRACKER_ID: u32 = 68;

fn init_header() -> HeaderMap {
    let mut headers = HeaderMap::new();
    headers.insert("Content-Type", "application/json".parse().unwrap());
    headers.insert(
        "X-Auth-AccessKey",
        "tlp-k1-5.605bf7a8dae7c732ff3207981e5f9ee60a275e8bc1f855a43471b204ff1e7ea3"
            .parse()
            .unwrap(),
    );
    headers
}

fn export_plan() {
    let plan = vec![
        String::from("20073"),
        // String::from("16423"),
        // String::from("16441"),
        // String::from("16579"),
        // String::from("16600"),
        // String::from("16612"),

        // String::from("17016"),
        // String::from("17194"),
    ];
    let mut tasks = Vec::<RowData>::new();

    let mut rt = tokio::runtime::Runtime::new().unwrap();

    let fn_detail = |id, headers, is_node| {
        rt.block_on(async {
            let mut r: Result<HashMap<String, Value>, _> = Result::Ok(HashMap::new());

            if is_node {
                r = artifact_linked_child(&id, headers).await;
            } else {
                r = artifact_detail(&id, headers).await;
            }
            match r {
                Ok(res) => res,
                Err(_) => HashMap::new(),
            }
        })
    };

    process_plans_to_row_data(&plan, &mut tasks, &fn_detail);

    println!("{:?}", tasks);

    export(tasks);
}


fn get_field_object_by_title(
    title: &HashMap<usize, String>,
) -> HashMap<String, Map<String, Value>> {
    let mut title_and_field_id = HashMap::<String, Map<String, Value>>::new();
    let artifact_detail = block_on(artifact_detail(&String::from("20911"), init_header()));

    if let Ok(data) = artifact_detail {
        // tracing::debug!("artifact_detail {:?}", data);
        let values = data.get("values").unwrap();

        match values {
            Value::Null => todo!(),
            Value::Bool(_) => todo!(),
            Value::Number(_) => todo!(),
            Value::String(_) => todo!(),
            Value::Array(vec) => {
                for v in vec {
                    match v {
                        Value::Null => todo!(),
                        Value::Bool(_) => todo!(),
                        Value::Number(_) => todo!(),
                        Value::String(_) => todo!(),
                        Value::Array(_) => todo!(),
                        Value::Object(o) => {
                            let k = o.get("label").unwrap();
                            let v = o.get("field_id").unwrap();
                            // tracing::debug!("key:{:?}-value:{:?}", k, v);
                            title_and_field_id.insert(k.as_str().unwrap().to_string(), o.clone());
                        }
                    }
                }
            }
            Value::Object(_) => todo!(),
        }
    }

    tracing::debug!("title_and_field_id:{:?}", title_and_field_id);
    title_and_field_id
}





#[tokio::main]
async fn main() {
    // RUST_LOG=trace cargo run
    if std::env::var_os("RUST_LOG").is_none() {
        std::env::set_var("RUST_LOG", "tuleap=trace");
    }

    tracing_subscriber::fmt::init();

    // let delete_ids = vec![21155	,
    // 21156	,
    // 21157	,
    // ];

    // for id in delete_ids{
    //     delete_artifact_by_id(&id, &init_header()).await;
    // }

    
    // let res = block_on(create_artifact(initHeader(), create_artifact_entity()));

    // match res {
    //     Ok(data) => println!("{:?}", data),
    //     Err(e)=>{println!("{:?}", e)}
    // }

    // let res = block_on(artifact_detail(&String::from("20912"),initHeader()));

    // match res {
    //     Ok(data) => println!("{:?}", data),
    //     Err(e)=>{println!("{:?}", e)}
    // }
}


fn process_plans_to_row_data<F: Fn(String, HeaderMap, bool) -> HashMap<String, Value>>(
    plan: &Vec<String>,
    tasks: &mut Vec<RowData>,
    detail: &F,
) {
    for artifact_id in plan {
        let plan_detail = detail(artifact_id.clone(), init_header(), false);
        let plan_title: String = plan_detail["title"].as_str().unwrap().to_string();

        process_artifact_to_row_data(&plan_title, artifact_id.clone(), tasks, detail);
    }
}

fn process_artifact_to_row_data<F: Fn(String, HeaderMap, bool) -> HashMap<String, Value>>(
    plan_title: &String,
    artifact_id: String,
    tasks: &mut Vec<RowData>,
    detail: &F,
) {
    let artifact_linked_childs_result = detail(artifact_id, init_header(), true);

    let childs = artifact_linked_childs_result["collection"]
        .as_array()
        .unwrap();

    for item in childs.iter() {
        let i_artifact_id = item["id"].as_u64().unwrap().to_string();
        let xref = item["xref"].as_str().unwrap().to_string();
        let mut p_title = item["title"].as_str().unwrap().to_string();

        p_title.insert_str(0, "=>");
        p_title.insert_str(0, plan_title.as_str());

        // sprint
        if xref.starts_with("sprint") {
            process_artifact_to_row_data(&p_title, i_artifact_id.clone(), tasks, detail);
        }
        // epic
        if xref.starts_with("epic") {
            process_artifact_to_row_data(&p_title, i_artifact_id.clone(), tasks, detail);
        }
        // story
        if xref.starts_with("story") {
            process_artifact_to_row_data(&p_title, i_artifact_id.clone(), tasks, detail);
        }
        // task
        if xref.starts_with("task") {
            let mut filed_value = HashMap::<String, String>::new();

            let values = item["values"].as_array().unwrap();
            for v in values {
                let field_label = v["label"].as_str().unwrap().to_string();
                let mut field_value = String::from("");
                match v.get("value") {
                    Some(vi) => match vi {
                        Value::Number(n) => field_value.push_str(n.to_string().as_str()),
                        Value::String(s) => field_value.push_str(s),
                        Value::Null => (),
                        _ => (),
                    },
                    None => (),
                }
                match v.get("values") {
                    Some(vi) => {
                        let vi_values = vi.as_array().unwrap();
                        if vi_values.len() == 1 {
                            let vi_v = &vi_values[0];
                            match vi_v.get("label") {
                                Some(s) => field_value.push_str(s.to_string().as_str()),
                                None => (),
                            }

                            match vi_v.get("real_name") {
                                Some(s) => match s.as_str() {
                                    Some(s) => field_value.push_str(s),
                                    None => (),
                                },
                                None => (),
                            }
                        }
                    }
                    None => (),
                }

                filed_value.insert(field_label, field_value);
            }

            tracing::debug!("filed_value:{:?}", filed_value);

            tasks.push(RowData::new_task_map(
                plan_title.clone(),
                p_title.clone(),
                filed_value,
            ));
        }
    }
}

fn getUrl() -> String {
    "https://192.168.1.20/".to_string()
}

// artifact 详情
async fn artifact_detail(
    id: &String,
    headers: HeaderMap,
) -> Result<HashMap<String, Value>, Box<dyn std::error::Error>> {
    let reqUrl = format!("{}api/artifacts/{}", getUrl(), id);

    tracing::debug!("request url:{:?}", reqUrl);

    let client = reqwest::Client::builder()
        .danger_accept_invalid_certs(true)
        .build()
        .unwrap();

    let mut data = HashMap::new();
    data.insert("values", "all");

    let resp = client
        .get(reqUrl)
        .headers(headers)
        .json(&data)
        .send()
        .await?
        .json::<HashMap<String, Value>>()
        .await?;
    Ok(resp)
}

// artifact： tracker 的集合
// https://192.168.1.20/api/artifacts/16091/linked_artifacts?direction=forward&nature=_is_child&limit=10
async fn artifact_linked_child(
    id: &String,
    headers: HeaderMap,
) -> Result<HashMap<String, Value>, Box<dyn std::error::Error>> {
    let reqUrl = format!(
        "{}api/artifacts/{}/linked_artifacts?direction=forward&nature=_is_child&limit=50",
        getUrl(),
        id
    );
    tracing::debug!("request url:{:?}", reqUrl);
    let client = reqwest::Client::builder()
        .danger_accept_invalid_certs(true)
        .build()
        .unwrap();

    let mut data = HashMap::new();
    data.insert("values", "all");

    let resp = client
        .get(reqUrl)
        .headers(headers)
        .json(&data)
        .send()
        .await?
        .json::<HashMap<String, Value>>()
        .await?;
    Ok(resp)
}

// tracker 详情
async fn tracker_detail(
    id: u32,
    headers: HeaderMap,
) -> Result<HashMap<String, Value>, Box<dyn std::error::Error>> {
    let reqUrl = format!("{}api/trackers/{}", getUrl(), id);

    tracing::debug!("request url:{:?}", reqUrl);

    let client = reqwest::Client::builder()
        .danger_accept_invalid_certs(true)
        .build()
        .unwrap();

    // let mut data = HashMap::new();
    // data.insert("values", "all");

    let resp = client
        .get(reqUrl)
        .headers(headers)
        // .json(&data)
        .send()
        .await?
        .json::<HashMap<String, Value>>()
        .await?;
    Ok(resp)
}
